package de.lmu.mvs.lerngruppenfinder.utils;

import java.io.IOException;
import java.util.HashMap;

import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;

import de.lmu.mvs.lerngruppenfinder.DashboardActivity;
import de.lmu.mvs.lerngruppenfinder.GroupDetailActivity;
import de.lmu.mvs.lerngruppenfinder.utils.FileApi.UserCredentials;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerConnectorListener;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerError;
import android.R;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

public class LocationService extends Service {

	private static final int MAX_UPDATE_TIME = 10000 * 6;

	public LocationManager mLocationManager;

	public MyLocationListener listener;

	public Location previousBestLocation = null;
	
	public Location currentLocation = null;

	private static final String TAG = LocationService.class.getSimpleName();

	public static final String BROADCAST_ACTION = "com.example.mvs_excercise_1_2.IMAGE_READY";

	private JsonArray jsonGroups = null;

	private long lastGroupUpdate = 0;

	private int mUserId = 0;

	private HashMap<Integer, Boolean> hsp = new HashMap<Integer, Boolean>();
	
	Intent intent;
	int counter = 0;

	@Override
	public void onCreate() {
		super.onCreate();
		intent = new Intent(BROADCAST_ACTION);  
	}

	@Override
	public void onStart(Intent intent, int startId) {      
		UserCredentials creds = FileApi.readLoginCredentials();
		mUserId = (creds != null) ? creds.id : 0;

		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		listener = new MyLocationListener();        
		mLocationManager.requestLocationUpdates(
				LocationManager.NETWORK_PROVIDER, 
				Constants.LOCATION_UPDATE_TIME,
				Constants.LOCATION_UPDATE_DISTANCE,				 
				listener);
		mLocationManager.requestLocationUpdates(
				LocationManager.GPS_PROVIDER, 
				Constants.LOCATION_UPDATE_TIME,
				Constants.LOCATION_UPDATE_DISTANCE, 
				listener);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	protected boolean isBetterLocation(Location location, Location currentBestLocation) {
		if (currentBestLocation == null) {
			previousBestLocation = location;
			currentLocation = location;
			return true;
		}
		if (currentBestLocation.equals(location)) {
			return false;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > MAX_UPDATE_TIME;
		boolean isSignificantlyOlder = timeDelta < -MAX_UPDATE_TIME;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and accuracy
		if (isMoreAccurate && isFromSameProvider) {
			return true;
		} else if (isNewer && !isLessAccurate && isFromSameProvider) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return true;
		}
		return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	@Override
	public void onDestroy() {       
		// handler.removeCallbacks(sendUpdatesToUI);     
		super.onDestroy();
		Log.v("STOP_SERVICE", "DONE");
		mLocationManager.removeUpdates(listener);        
	}   

	public static Thread performOnBackgroundThread(final Runnable runnable) {
		final Thread t = new Thread() {
			@Override
			public void run() {
				try {
					runnable.run();
				} finally {

				}
			}
		};
		t.start();
		return t;
	}


	public class MyLocationListener implements LocationListener
	{
		public void onLocationChanged(final Location loc)
		{
			Log.i("**************************************", "Location changed");

			if(jsonGroups == null || System.currentTimeMillis() - lastGroupUpdate > MAX_UPDATE_TIME ){
				updateGroups();
			}
			else if(jsonGroups != null && isBetterLocation(loc, previousBestLocation)) {
				checkDistanceToGroups(jsonGroups);
			}
		}

		public void onProviderDisabled(String provider)
		{
			Log.i("GPS", "GPS disabled");
		}


		public void onProviderEnabled(String provider)
		{
			Toast.makeText( getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show();
		}


		public void onStatusChanged(String provider, int status, Bundle extras)
		{

		}


		private void updateGroups(){
			Log.d(TAG, "Update subscribed groups list");

			if(mUserId != 0){
				ServerConnector.getSubscribedGroups(new ServerConnectorListener<JsonArray>() {

					@Override
					public void requestFinished(JsonArray json) {
						jsonGroups = json;
						lastGroupUpdate = System.currentTimeMillis();
						try {
							FileApi.writeJsonToStorage(json, Constants.SUBSCRIBED_GROUPS, getBaseContext());
							Log.d(TAG, "Subscribed groups updated");
						} catch (IOException e) {
							e.printStackTrace();
						}
					}

					@Override
					public void requestError(ServerError error) {
						Log.e(TAG, error.getErrorMessage());
					}
				}, mUserId);
			} else {
				jsonGroups = null;
			}
		}

		private void checkDistanceToGroups(JsonArray json) {
			Log.i("DISTANCE", "blub");
			for (JsonValue jsonValue : json) {
				try {
					double lat = Double.parseDouble(jsonValue.asObject().get(Constants.JSON_LATITUDE).asString());
					double lon = Double.parseDouble(jsonValue.asObject().get(Constants.JSON_LONGITUDE).asString());
					int id = Integer.parseInt(jsonValue.asObject().get(Constants.JSON_GROUP_ID).asString());

					float[] distance = new float[1];
					
					Location.distanceBetween(
							currentLocation.getLatitude(),
							currentLocation.getLongitude(), 
							lat, 
							lon, 
							distance);
				 
					if (hsp.containsKey(id) && distance[0] > Constants.NOTIFICATION_DISTANCE)
					{
						hsp.remove(id);
					}
					
					if(distance != null && distance.length > 0 && distance[0] < Constants.NOTIFICATION_DISTANCE && !hsp.containsKey(id)){
						sendNotification(id);
					}
				} catch(NumberFormatException e){
					// skip
					Log.w("DISTANCE", e.getMessage());
					e.printStackTrace();
				}
			}
		}

		private void sendNotification(int id) {
			NotificationManager notificationManager = (NotificationManager) 
					getSystemService(NOTIFICATION_SERVICE);

			hsp.put(id, true);
			// prepare intent which is triggered if the
			// notification is selected
			Intent intent = new Intent(getBaseContext(), DashboardActivity.class);
			PendingIntent pIntent = PendingIntent.getActivity(getBaseContext(), 0, intent, 0);

			// build notification
			// the addAction re-use the same intent to keep the example short
			NotificationCompat.Builder n  = new NotificationCompat.Builder(getBaseContext())
			.setContentTitle("Learning group in your Nähe!")
			.setContentText("Subject")
			.setSmallIcon(R.drawable.ic_media_play)
			.setContentIntent(pIntent)
			.setAutoCancel(true);
//			.addAction(R.drawable.icon, "Call", pIntent)
//			.addAction(R.drawable.icon, "More", pIntent)

			notificationManager.notify(id, n.build());

			
			Log.d(TAG, "Notification added");
		}
	}

}
